package com.kayak.kboot.dao;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
import com.kayak.exception.ErrorException;
import com.kayak.kboot.dao.kSql.SqlResult;
import com.kayak.kboot.dao.kSql.SqlRow;
import com.kayak.kboot.dao.kSql.SqlStatement;
import com.kayak.kboot.dao.kSql.SqlUtil;
import com.kayak.kboot.dao.kSql.object.SqlConfig;
import com.kayak.kkutils.Tools;

/**
 *1.多数据源comnDao 和 secondDao 的基础
 *2.通过druid的配置类中的事务管理器注入了jdbcTemplate，dbtype，nickName
 *3.只能执行 query  update，不支持批量,批量请使用KTransaction
 * @author caix
 *
 */
public  class BaseDao  {
	
	public DataSourceTransactionManager transactionManager;
    public JdbcTemplate jdbcTemplate;
    public String dbType;
    public String nickName;
    
    
	
	private static Logger log = LoggerFactory.getLogger(BaseDao.class);

	public BaseDao(DataSourceTransactionManager transactionManager) {
		super();
		this.transactionManager=transactionManager;
		this.jdbcTemplate=new JdbcTemplate(transactionManager.getDataSource());
		this.dbType=((DruidDataSource)this.jdbcTemplate.getDataSource()).getDbType();
		this.nickName=((DruidDataSource)this.jdbcTemplate.getDataSource()).getName();
	}


	/**
	 * 执行查询并返回SqlResult结果集<br />
	 * 在执行查询前，必须给params成员设置值<br />
	 * 通用查询只支持指定exeid
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @return 查询结果集，出错返回null
	 * @throws ErrorException
	 */
	public SqlResult query(String exeid, Map<String, Object> params) throws ErrorException {
		return query(exeid, params, null, null);
	}


	/**
	 * 执行查询并返回SqlResult结果集<br />
	 * 在执行查询前，必须给params成员设置值<br />
	 * 通用查询只支持指定exeid
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @param start
	 *            起始记录，如果传null或小于零的值，则忽略该参数
	 * @param limit
	 *            最大记录数，如果传null或小于1的值，则忽略该参数
	 * @return 查询结果集，出错返回null
	 * @throws ErrorException
	 */
	public SqlResult query(String sqlid, Map<String, Object> params, Integer start, Integer limit)
			throws ErrorException {
		if (params == null)
			params = new HashMap<String, Object>();

		if (sqlid == null)
			throw new ErrorException("sqlid is null");
			

		// 取得SQL配置信息
		SqlConfig sqlconfig = SqlManager.getSqlid(sqlid);
		if (sqlconfig == null)
			throw new ErrorException("找不到 sqlid : " + sqlid);

		try {
			
			if(start==null){
				params.remove("start");
			}
			if(limit==null){
				params.remove("limit");
			}
			
			if (start != null && start > -1)
				params.put("start", start);
			if (limit != null && limit > 0)
				params.put("limit", limit);

			// 执行通用查询语句
			SqlStatement stm = new SqlStatement(sqlconfig.getSql(this.dbType), jdbcTemplate);
			stm.autoSetParams(params);
			SqlResult result = stm.executeQuery();
			log.info("["+this.nickName+"]["+this.dbType+"] end query : sqlid： "+ sqlid);
			return result;
		} catch (Exception e) {
			//tx.rollback();
			log.error(e.getMessage());
			e.printStackTrace();
			throw new ErrorException(e.getMessage());
		} finally {
			//this.releaseSession(session);// 所有方法必须使用这个方法释放session资源
		}
	}

	/**
	 * 执行查询（只查记录总数）并返回SqlResult结果集<br />
	 * 在执行查询前，必须给params成员设置值<br />
	 * 通用查询只支持指定exeid
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @return 查询结果集，出错返回null
	 * @throws ErrorException
	 */
	public SqlResult queryCount(String exeid, Map<String, Object> params) throws ErrorException {
		return queryCount(exeid, params, SqlUtil.obj2Integer(params.get("start")),
				SqlUtil.obj2Integer(params.get("limit")));
	}

	/**
	 * 执行查询（只查记录总数）并返回SqlResult结果集<br />
	 * 在执行查询前，必须给params成员设置值<br />
	 * 通用查询只支持指定exeid
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @return 查询结果集，出错返回null
	 * @throws ErrorException
	 */
	public SqlResult queryCount(String sqlid, Map<String, Object> params, Integer start, Integer limit)
			throws ErrorException {
		if (params == null)
			params = new HashMap<String, Object>();

		if (sqlid == null)
			throw new ErrorException("sqlid is null");
			

		// 取得SQL配置信息
		SqlConfig sqlconfig = SqlManager.getSqlid(sqlid);
		if (sqlconfig == null)
			throw new ErrorException("找不到 sqlid : " + sqlid);

		try {
			// 执行通用查询语句
			SqlStatement stm = new SqlStatement(sqlconfig.getSql(this.dbType), jdbcTemplate);
			stm.autoSetParams(params);
			Long count = stm.executeCountQuery();
			log.info("["+this.nickName+"]["+this.dbType+"] end queryCount : sqlid： "+ sqlid);
			SqlResult result = new SqlResult();
			if(start==null){
				params.remove("start");
			}
			if(limit==null){
				params.remove("limit");
			}

			if (start == null || start < 0)
				start = 0;
			if (limit == null || limit < 1)
				limit = count.intValue();
			double end = Math.min(start + limit, count);
			for (; start < end; start++) {
				result.addRow(new SqlRow());
			}

			result.setCount(count);

			return result;
		} catch (Exception e) {
			log.error(e.getMessage());
			e.printStackTrace();
			throw new ErrorException(e.getMessage());
		} finally {
			
		}
	}

	/**
	 * 执行通用SQL更新<br />
	 * 在执行更新前，必须给params成员设置值<br />
	 * 通用查询只支持指定exeid
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @return 返回处理结果信息，出错返回null
	 * @throws ErrorException
	 * @throws ErrorException
	 */
	public int update(String exeid, final Map<String, Object> params) throws ErrorException, ErrorException {
		if (params != null) {
			if (exeid == null)
				exeid = Tools.trimString(params.get("exeid"));
			else
				params.put("exeid", exeid);
		}
		return doUpdate(exeid, params);
	}



	/**
	 * 执行通用SQL更新
	 *
	 * @param exeid
	 *            如果指定exeid则执行exeid指定的通用SQL，否则尝试从params中取得exeid参数来使用
	 * @return 返回处理结果信息，出错返回null
	 * @throws ErrorException
	 *             在SQL校验检查失败时，抛出相应的错误信息，在调用此方法时，必须处理这个错误信息（如返回提示给用户）
	 * @throws ErrorException
	 */
	private int doUpdate(String sqlid, final Map<String, Object> params) throws ErrorException, ErrorException {
		// 读取SQL配置
		int ret =0;
		if (sqlid == null)
			throw new ErrorException("sqlid is null");
		else
			


		try {
			SqlConfig sqlconfig = SqlManager.getSqlid(sqlid);
			log.info("["+this.nickName+"]["+this.dbType+"] update sqlid : " + sqlid );
			// 准备更新执行
			SqlStatement stmExecute = new SqlStatement(sqlconfig.getSql(this.dbType), jdbcTemplate);
			stmExecute.autoSetParams(params, false);
			ret = stmExecute.executeUpdate();
			
			return ret;
		} catch (Exception e) {
			e.printStackTrace();
			String msg = sqlid + "失败：" + e.getMessage();
			log.error(e.getMessage());
			if (e instanceof ErrorException) {
				// 如果是校验检查失败，抛出错误信息
				throw (ErrorException) e;
			} else {
				// 插入失败也抛出错误信息
				log.error("数据库更新失败" + e.getMessage());
				throw new ErrorException(e.getMessage());
			}

		} finally {
		}
	}



	public SqlStatement newSqlStatement(String sql) throws ErrorException, SQLException{
		return new SqlStatement(sql, jdbcTemplate);
	}
	
	












}
